#pragma once
#include "execution_defs.h"
#include "execution_manager.h"
#include "executor_abstract.h"
#include "index/ix.h"
#include "system/sm.h"

class ProjectionExecutor : public AbstractExecutor {
   private:
    std::unique_ptr<AbstractExecutor> prev_;
    std::vector<ColMeta> cols_;
    size_t len_;
    std::vector<size_t> sel_idxs_;

   public:
    ProjectionExecutor(std::unique_ptr<AbstractExecutor> prev, const std::vector<TabCol> &sel_cols) {
        prev_ = std::move(prev);

        size_t curr_offset = 0;
        auto &prev_cols = prev_->cols();
        for (auto &sel_col : sel_cols) {
            auto pos = get_col(prev_cols, sel_col);
            sel_idxs_.push_back(pos - prev_cols.begin());
            auto col = *pos;
            col.offset = curr_offset;
            curr_offset += col.len;
            cols_.push_back(col);
        }
        len_ = curr_offset;
    }

    std::string getType() override { return "Projection"; }

    size_t tupleLen() const override { return len_; }

    const std::vector<ColMeta> &cols() const override { return cols_; }

    void beginTuple() override { prev_->beginTuple(); }

    void nextTuple() override {
        assert(!prev_->is_end());
        prev_->nextTuple();
    }

    bool is_end() const override { return prev_->is_end(); }

    std::unique_ptr<RmRecord> Next() override {
        // 负责从上一个操作符（算子）获取记录，并根据投影列的要求创建一个新的记录。
        assert(!is_end());// 断言当前没有到达扫描的末尾
        auto &prev_cols = prev_->cols();// 获取上一个算子的列信息
        auto prev_rec = prev_->Next();// 从上一个算子获取下一条记录
        auto &proj_cols = cols_;// 获取当前投影操作的列信息
        auto proj_rec = std::make_unique<RmRecord>(len_);// 创建一个新的记录对象，用于存储投影结果，长度为len_
        for (size_t proj_idx = 0; proj_idx < proj_cols.size(); proj_idx++) {// 遍历投影列
            size_t prev_idx = sel_idxs_[proj_idx];// 获取当前投影列在原始记录中对应列的索引
            auto &prev_col = prev_cols[prev_idx];// 获取原始记录中对应列的信息
            auto &proj_col = proj_cols[proj_idx];// 获取投影列的信息
            // lab3 task2 Todo
            // 利用memcpy生成proj_rec
            // lab3 task2 Todo End
            memcpy(proj_rec->data + proj_col.offset, prev_rec->data + prev_col.offset, proj_col.len);// 将原始记录中的对应列数据复制到投影记录的相应位置
        }
        return proj_rec;// 返回投影后的新记录对象
    }

    void feed(const std::map<TabCol, Value> &feed_dict) override {
        throw InternalError("Cannot feed a projection node");
    }
    Rid &rid() override { return _abstract_rid; }
};